/*made by alex, compile with pthread flag (-pthread for gcc)*/
#include <curses.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <pthread.h>
int returnResults(void);
int extendArray(int size2, int buffsize,int buffincrement);
void *checkPrime(void *threadarg);
int *primes,prime,count, *temp;

struct thread_data{
	int temp_id;
	int prime;
};

int main(int argc,char **argv){
int max,buffsize, maxfork,children,i,increment;
bool verbose=0;
maxfork=40;
max=30;
increment=100;
buffsize=100;
for(i=1;i<argc;i++){
if(argv[i][0]=='-'){
switch(argv[i][1]){
	case 'b':
	if(argv[i+1]!=NULL)
	buffsize=atoi(argv[i+1]);
	break;
	case 's':
	if(argv[i+1]!=NULL)
	max=atoi(argv[i+1]);
	break;
	case 't':
	if(argv[i+1]!=NULL)
	maxfork=atoi(argv[i+1]);
	case 'v':
	verbose=1;
	break;
	case 'h':
	printf("Usage: proggy -s 10000\n\t-b\tset buffersize\tless need to update buffer/bigger mem use\n\t-s\tset max nr\tpick the number until where you want to calculate all primes\n\t-t\tset max threads\trecommended to set this pretty high, default is 40\n\t-v\tset verbosity\n\t-h\tcall 911\n");
	return 1;
	default:break;
}
}
}
if(maxfork<2 || maxfork%2!=0){printf("Bare minimum of threads is 2,and has to be a multitude of 2\nSetting to default\n\n");maxfork=40;}
printf("btw: if you want to see the help use -h\n\nLoading buffers\n\n");
pthread_t thread_id[maxfork];
struct thread_data thread_args_array[maxfork];
temp=calloc(maxfork, sizeof(int *));
primes=malloc(buffsize * sizeof(int *));
primes[0]=5;
/*test stuff
*/
printf("Calculating until: %i\n", max);
prime=1;
count=0;
children=-1;
bool running=1;
while (running){
	while (prime*6+5<=primes[count]*5 && children < maxfork-2 && prime<max/6){
		children+=2;
		thread_args_array[children-1].temp_id=children-1;
		thread_args_array[children-1].prime=prime*6+1;
		thread_args_array[children].temp_id=children;
		thread_args_array[children].prime=prime*6+5;
		if(pthread_create(&thread_id[children-1],NULL,checkPrime,(void *) &thread_args_array[children-1]) != 0 || pthread_create(&thread_id[children],NULL,checkPrime,(void *) &thread_args_array[children]) !=0){
		printf("pthread error, quitting\n");
		return 1;
		}
		prime++;
	}
for(i=0;i<=children;i++){
		pthread_join(thread_id[i], NULL);
		}
children=-1;
if(extendArray(maxfork, buffsize,increment)!=0){
	printf("Could not allocte more memory to primes array, quitting\n");
	return 1;}
memset(temp,0,maxfork*sizeof(int *));
/*printf("Current prime: %i\nGoal: %i\n",prime,max/6);
printf("printing temp after memset\n");
for(i=0;i<maxfork;i++){
printf("temp[%i]=%i\n",i,temp[i]);
}*/
if(prime>=max/6)
running=0;
}
returnResults();
free(primes);
free(temp);
return 0;
}


int returnResults(void){
printf("\n\nPrime numbers found:\n2,3");
int i;
for(i=0;i<count;i++){
printf(",%i",primes[i]);
}
printf("\n");
return 0;
}


int extendArray(int size2, int buffsize,int buffincrement){
int i=0;
check:
while(i<size2 && count<buffsize-1){
if(temp[i]!=0){
		count++;
		primes[count]=temp[i];
	}
	i++;
}
if(i>=size2){
return 0;
}else{
int *tmp = realloc(primes,(buffsize+buffincrement)*sizeof(int *));
if (tmp != NULL){
buffsize=buffsize+buffincrement;
primes=tmp;
}
else{
return 1;
}
goto check;
}
printf("why am I here??\n");
return 0;
}


void *checkPrime(void *threadarg){
struct thread_data *my_data;
my_data= (struct thread_data *) threadarg;
/*temp[my_data->temp_id]=0;
printf("got in checkprime: job %i\n",my_data->prime);*/
int i;
for(i=0;primes[i]<=my_data->prime/5;i++){
/*printf("job %i checking against %i\n",my_data->prime,primes[i]);*/
if(my_data->prime%primes[i]==0){
/*	printf("prime job %i, NOT A PRIME\n",my_data->prime);*/
pthread_exit(NULL);
}
}
temp[my_data->temp_id]=my_data->prime;
/*printf("prime job %i, FOUND PRIME\n",my_data->prime);*/
pthread_exit(NULL);
}
